#include "ItemModel.h"
#include "ValueItem.h"
#include "RootItem.h"
#include "ReferenceItem.h"


#include <QDebug>



ItemModel::ItemModel(QObject* parent)
    : QAbstractItemModel(parent)
{
}



ItemModel::ItemModel(RootItem *root, QObject *parent)
    : QAbstractItemModel(parent)
{
    setRootItem(root);
}



ItemModel::~ItemModel()
{
}



AbstractItem* ItemModel::indexItem(const QModelIndex& index) const
{
    return dynamic_cast<AbstractItem*>(static_cast<QObject*>(index.internalPointer()));
}


RootItem* ItemModel::rootItem() const
{
    return m_root.data();
}



void ItemModel::setRootItem(RootItem* root)
{
    emit layoutAboutToBeChanged();
    if (!m_root.isNull())
    {
        disconnect(m_root.data(), SIGNAL(sigDirty()), this, SIGNAL(layoutChanged()));
    }

    m_root = dynamic_cast<RootItem*>(root);
    if (!m_root.isNull())  connect(m_root.data(), SIGNAL(sigDirty()), this, SIGNAL(layoutChanged()));

    emit layoutChanged();
}



QModelIndex ItemModel::index(int row, int column, const QModelIndex &parent) const
{
    if (m_root.isNull()) return QModelIndex();
    if (!hasIndex(row, column, parent)) return QModelIndex();

    AbstractItem* parentItem = 0;
    if (!parent.isValid())
    {
        parentItem = m_root.data();
    }
    else
    {
        parentItem = indexItem(parent);
    }

    if (!parentItem || parentItem->itemCount() <= row) return QModelIndex();

    AbstractItem* item = parentItem->itemAt(row);
    if (!item) return QModelIndex();

    return createIndex(row, column, item);
}



QModelIndex ItemModel::parent(const QModelIndex &child) const
{
    if (m_root.isNull() || !child.isValid()) return QModelIndex();

    AbstractItem* childItem = indexItem(child);
    if (!childItem || childItem == rootItem()) return QModelIndex();

    AbstractItem* item = qobject_cast<AbstractItem*>(childItem->parent());
    if (!item || !item->parent() || item == rootItem()) return QModelIndex();


    int row = item->parent()->children().indexOf(item);
    return createIndex(row, 0, item);
}


int ItemModel::rowCount(const QModelIndex &parent) const
{
    if (m_root.isNull()) return 0;

    AbstractItem* item = 0;

    if (!parent.isValid())
    {
        item = m_root.data();
    }
    else
    {
        item = indexItem(parent);
    }

    if (!item) return 0;

    return item->itemCount();
}



int ItemModel::columnCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent);

    if (m_root.isNull()) return 0;

    int ret = 0;
    foreach (AbstractItem* item, m_root->findChildren<AbstractItem*>())
    {
        if (!item) continue;
        if (item->fieldCount() > ret) ret = item->fieldCount();
    }

    return ret;
}



QVariant ItemModel::data(const QModelIndex &index, int role) const
{
    if (role != Qt::DisplayRole && role != Qt::EditRole) return QVariant();
    if (m_root.isNull() || !index.isValid()) return QVariant();

    AbstractItem* item = indexItem(index);

    if (!item || item == rootItem()) return QVariant();

    return item->data(index.column(), role);

}



bool ItemModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    if (!index.isValid() || role != Qt::EditRole) return false;

    AbstractItem* item = indexItem(index);
    if (!item) return false;

    //emit layoutAboutToBeChanged();
    item->setData(index.column(), value);
    emit dataChanged(index, index);
    //emit layoutChanged();
    return true;
}


QVariant ItemModel::headerData(int section, Qt::Orientation orientation, int role) const
{
    Q_UNUSED(orientation);

    if (role != Qt::DisplayRole) return QVariant();

    if (section < 0 || section >= columnCount(QModelIndex())) return QVariant();

    // todo: all data type names to common defines.
    switch (section)
    {
    case AbstractItem::IdData:          return tr("Id");
    case AbstractItem::NameData:        return tr("Name");
    case AbstractItem::DescData:        return tr("Description");
    case AbstractItem::CategoryData:    return tr("Type");

    case ValueItem::ValueData:          return tr("Value");
    case ReferenceItem::ReferenceData:  return tr("Referenced Item");
    default:                            return tr("Unknown Field");
    }
}


Qt::ItemFlags ItemModel::flags(const QModelIndex &index) const
{
    switch (index.column())
    {
    case AbstractItem::IdData:      return QAbstractItemModel::flags(index);
    case AbstractItem::CategoryData:    return QAbstractItemModel::flags(index);
    }

    AbstractItem* item = indexItem(index);
    if (item->rootItem() != rootItem()) return QAbstractItemModel::flags(index);

    return QAbstractItemModel::flags(index) | Qt::ItemIsEditable;
}


int ItemModel::addItem(AbstractItem* item, const QModelIndex& parent)
{
    if (m_root.isNull()) return -1;

    AbstractItem* parentItem = indexItem(parent);
    if (!parentItem) parentItem = m_root.data();

    if (IS_REFERENCE(item) && (IS_REFERENCE(parentItem) || IS_ROOT(parentItem))) return -1;

    if (item->parent()) disconnect(item->parent(), SIGNAL(sigDirty()));
    item->setParent(parentItem);
    item->setData(AbstractItem::IdData);
    connect(item, SIGNAL(sigDirty()), parentItem, SIGNAL(sigDirty()));

    int row = parentItem->children().indexOf(item);

    beginInsertRows(parent, row, row);
//    QModelIndex first = index(row, 0, parent);
//    QModelIndex last = index(row, columnCount(parent), parent);
    endInsertRows();

//    emit dataChanged(parent, first);
    emit layoutChanged();

    m_root->setDirty(true);
    return row;
}


bool ItemModel::removeRows(int row, int count, const QModelIndex &parent)
{
    if (m_root.isNull()) return false;

    AbstractItem* item = 0;
    if (!parent.isValid())
    {
        item = m_root.data();
    }
    else
    {
        item = indexItem(parent);
    }

    if (!item) return false;

    // r = 3, c = 3
    // f = 3
    // l = 5

    int first = row;
    int last = row+count-1;

    beginRemoveRows(parent, first, last);
    for (int i = row; i < row+count; i++)
    {
        item->removeAt(i);
    }
    endRemoveRows();

    emit dataChanged(index(0,0,parent), index(rowCount(parent), columnCount(parent), parent));
    return true;

//    return removeRow(row, parent);


}


//bool ItemModel::removeRow(int row, const QModelIndex &parent)
//{
//}



//QModelIndex ItemModel::referencedIndex(const QModelIndex& reference) const
//{
//    if (!rootItem() || !reference.isValid()) return QModelIndex();

//    QModelIndex searchIndex = index(0, AbstractItem::IdData, QModelIndex());
//    if (!searchIndex.isValid()) return QModelIndex();

//    QModelIndex typeIndex = reference.sibling(reference.row(), AbstractItem::CategoryData);
//    if (!typeIndex.isValid()) return QModelIndex();

//    int type = typeIndex.data(Qt::EditRole).toInt();
//    if (!IS_REFERENCE_TYPE(type)) return QModelIndex();

//    QModelIndex referenceIndex = reference.sibling(reference.row(), ReferenceItem::ReferenceData);
//    if (!referenceIndex.isValid()) return QModelIndex();

//    QModelIndexList foundIndexes = match(searchIndex,
//                                         Qt::EditRole,
//                                         referenceIndex.data(Qt::EditRole),
//                                         1,
//                                         Qt::MatchExactly | Qt::MatchRecursive);

//    if (foundIndexes.isEmpty()) return QModelIndex();

//    return foundIndexes.first();

//}
